import type { LineString } from 'geojson'
import { keyGen } from '@/common'
import { bearing, destination, distance, type LngLat } from '@/geom/great-circle'
import { type LineFeature, type MapFeatures, type SymbolFeature, symbolProperties } from '@/map'
import { auxGraphicStyle, type AuxGraphic, addAuxGraphic } from '../core'
import { meter2MetricStr } from '@/widgets'
import { auxGraphicProperties } from '../core/base'

export interface AuxLinePoint {
  point: LngLat
  length: number
}

export interface AuxLine extends AuxGraphic {
  type: 'Line'
  length: number
  course: number
  start: LngLat
  end: LngLat
  points: AuxLinePoint[]
}

const nameGen = keyGen('测量线#')

function nextName(): string {
  return nameGen.next()
}

export function addAuxLine(start: LngLat, end: LngLat) {
  addAuxGraphic(makeAuxLine(start, end))
}

export function makeAuxLine(start: LngLat, end: LngLat): Omit<AuxLine, 'id'> {
  const length = distance(start, end)
  const course = bearing(start, end)

  let interval = length
  let k = 500
  while (k < 50000000) {
    if (length <= k) {
      interval = k / 50.0
      break
    }
    k *= 10
  }
  const points: AuxLinePoint[] = []
  points.push({ point: start, length: 0 })
  let len = interval
  while (len < length) {
    const mp = destination(start, course, len)
    points.push({ point: mp, length: len })
    len += interval
  }
  points.push({ point: end, length })
  return {
    type: 'Line',
    name: nextName(),
    start,
    end,
    length,
    course,
    points
  }
}

export function toLineString(al: AuxLine): LineString {
  const { start, end, length, points } = al
  if (length < 100000) {
    return {
      type: 'LineString',
      coordinates: [
        [start.lng, start.lat],
        [end.lng, end.lat]
      ]
    }
  }

  return {
    type: 'LineString',
    coordinates: points.map((pt) => [pt.point.lng, pt.point.lat])
  }
}

export function toFeature(al: AuxLine, g: LineString[]): MapFeatures {
  const symbolStyle = auxGraphicStyle.symbol
  const symbol: SymbolFeature[] = []
  const { course, points } = al
  for (let i = 0; i < points.length; i++) {
    const pt = points[i]
    let txt: string | undefined = undefined
    if (i === 0) {
      // txt = `${al.name}\n `
      txt = `${al.name}`
    } else if (i === points.length - 1) {
      // txt = `${formatLen(pt.length)}/${Math.floor(course)}°\n `
      txt = `${meter2MetricStr(pt.length)}/${Math.round(course)}°`
    } else if (i % 5 === 0) {
      txt = meter2MetricStr(pt.length)
    }
    const loc = pt.point
    symbol.push({
      type: 'Feature',
      geometry: {
        type: 'Point',
        coordinates: [loc.lng, loc.lat]
      },
      properties: symbolProperties(txt, symbolStyle)
    })
  }
  const ls = g.length > 0 ? g[0] : toLineString(al)
  const line: LineFeature[] = [
    {
      type: 'Feature',
      geometry: ls,
      properties: auxGraphicProperties.line
    }
  ]

  return { symbol, line }
}
